package com.trt.beibei.logic;

import com.trt.beibei.bo.SkuOrderBO;
import com.trt.beibei.core.enumeration.CouponType;
import com.trt.beibei.core.money.IMoneyDiscount;
import com.trt.beibei.exception.http.ForbiddenException;
import com.trt.beibei.exception.http.ParameterException;
import com.trt.beibei.model.Category;
import com.trt.beibei.model.Coupon;
import com.trt.beibei.util.CommonUtil;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <h1>校验优惠券数据</h1>
 */
public class CouponChecker {

    private Coupon coupon;

    private IMoneyDiscount iMoneyDiscount;

    public CouponChecker(Coupon coupon,IMoneyDiscount iMoneyDiscount) {
        this.coupon = coupon;
        this.iMoneyDiscount = iMoneyDiscount;
    }

    public void isOk() {
        Date now = new Date();
        Boolean isInTimeline = CommonUtil.isInTimeLine(now, coupon.getStartTime(), coupon.getEndTime());
        if (!isInTimeline) {
            throw new ForbiddenException(40007);
        }
    }

    public void finalTotalPriceIsOk(BigDecimal orderFinalTotalPrice,
                                    BigDecimal serverTotalPrice) {
        BigDecimal serverFinalTotalPrice;

        switch (CouponType.toType(coupon.getType())) {
            case FULL_MINUS:
            case NO_THRESHOLD_MINUS:
                serverFinalTotalPrice = serverTotalPrice.subtract(coupon.getMinus());
                if (serverFinalTotalPrice.compareTo(new BigDecimal("0")) <= 0) {
                    throw new ForbiddenException(50008);
                }
                break;
            case FULL_OFF:
                serverFinalTotalPrice = iMoneyDiscount.discount(serverTotalPrice, coupon.getRate());
                break;
            default:
                throw new ParameterException(40009);
        }
        int compare = serverFinalTotalPrice.compareTo(orderFinalTotalPrice);
        if (compare != 0) {
            throw new ForbiddenException(50008);
        }
    }

    public void canBeUsed(List<SkuOrderBO> skuOrderBOList, BigDecimal serverTotalPrice) {
        BigDecimal orderCategoryPrice;

        // 没分类情况
        if(coupon.getWholeStore()){
            orderCategoryPrice = serverTotalPrice;
        }
        // 多分类情况
        else{
            List<Long> cidList = coupon.getCategoryList()
                    .stream()
                    //.map(category -> category.getId())
                    .map(Category::getId)
                    .collect(Collectors.toList());
            orderCategoryPrice = getSumByCategoryList(skuOrderBOList, cidList);
        }
        couponCanBeUsed(orderCategoryPrice);
    }

    private BigDecimal getSumByCategoryList(List<SkuOrderBO> skuOrderBOList, List<Long> cidList) {
        BigDecimal sum = cidList.stream()
                .map(cid -> getSumByCategory(skuOrderBOList, cid))
                .reduce(BigDecimal::add)
                .orElse(new BigDecimal("0"));
        return sum;
    }

//    private BigDecimal getSumByCategory(List<SkuOrderBO> skuOrderBOList, Long cid) {
//        boolean seen = false;
//        BigDecimal acc = null;
//        for (SkuOrderBO sku : skuOrderBOList) {
//            if (sku.getCategoryId().equals(cid)) {
//                BigDecimal totalPrice = sku.getTotalPrice();
//                if (!seen) {
//                    seen = true;
//                    acc = totalPrice;
//                } else {
//                    acc = acc.add(totalPrice);
//                }
//            }
//        }
//        BigDecimal sum = seen ? acc : new BigDecimal("0");
//        return sum;
//    }
    private BigDecimal getSumByCategory(List<SkuOrderBO> skuOrderBOList, Long cid) {
        BigDecimal sum = skuOrderBOList.stream()
                .filter(sku -> sku.getCategoryId().equals(cid))
                .map(SkuOrderBO::getTotalPrice)
                //.reduce((bigDecimal, augend) -> bigDecimal.add(augend)) lambda表达式
                .reduce(BigDecimal::add) // 方法引用
                .orElse(new BigDecimal("0"));
        return sum;
    }

    private void couponCanBeUsed(BigDecimal orderCategoryPrice) {
        switch (CouponType.toType(coupon.getType())){
            case FULL_OFF:
            case FULL_MINUS:
                int compare = coupon.getFullMoney().compareTo(orderCategoryPrice);
                if(compare > 0){
                    throw new ParameterException(40008);
                }
                break;
            case NO_THRESHOLD_MINUS:
                break;
            default:
                throw new ParameterException(40009);
        }
    }


}


